package com.syncomponents.spi.jms;

import java.io.Serializable;

import javax.annotation.Resource;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.listener.SessionAwareMessageListener;
import org.springframework.stereotype.Component;

import com.syncomponents.context.SynFactory;
import com.syncomponents.context.support.HandlerType;
import com.syncomponents.context.support.MessageHandler;
import com.syncomponents.core.MessageConstant;
import com.syncomponents.core.ServiceException;
import com.syncomponents.util.MessageUtil;

/**
 * 消息监听
 * 
 * @author sunkey
 * @date Jan 15, 2014
 */
@Component
public class SynMessageListener implements SessionAwareMessageListener<TextMessage> {

    private final Logger logger = LoggerFactory.getLogger(SynMessageListener.class);

    @Resource
    private SynFactory<MessageHandler> handlerFactory;

    @Resource
    private JmsTemplate jmsTemplate;

    @Override
    public void onMessage(final TextMessage message, Session session) throws JMSException {
        long start = System.currentTimeMillis();
        String msg = message.getText();
        
        if (msg == null) {
            throw new JMSException("message text is null");
        }
        
//        String msgType = message.getJMSCorrelationID();
//        String action = message.getStringProperty(MessageConstant.MESSAGE_ACTION);

        try {
            MessageHandler messageHandler = handlerFactory.getBean(HandlerType.identifyHanderType(msg).getValue());
            if (messageHandler == null) {
                throw new ServiceException("The message format is not supported");
            }
            final Object response = messageHandler.handle(msg);
            if (null != message.getJMSReplyTo()) {

                if (response == null) {
                    replyFailureMsg(message, session, msg, "response is null");
                } else {

                    MessageCreator messageCreator = new MessageCreator() {
                        public Message createMessage(Session session) throws JMSException {
                            Message replyMessage = null;
                            if (response instanceof String) {
                                logger.info("replying TextMessage");
                                replyMessage = session.createTextMessage(response.toString());
                            } else {
                                logger.info("replying  objectMessage");
                                ObjectMessage objectMessage = session.createObjectMessage();
                                objectMessage.setObject((Serializable) response);
                                replyMessage = objectMessage;
                            }
                            replyMessage.setJMSCorrelationID(message.getJMSMessageID());
                            replyMessage.setStringProperty(
                                    MessageConstant.MESSAGE_ACTION,
                                    message.getJMSCorrelationID() + "."
                                            + message.getStringProperty(MessageConstant.MESSAGE_ACTION));
                            return replyMessage;
                        }
                    };

                    jmsTemplate.send(message.getJMSReplyTo(), messageCreator);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            replyFailureMsg(message, session, msg, e.getMessage());
        } finally {
            long end = System.currentTimeMillis();
            logger.info("elapsed time:(ms)" + (end - start));
        }

    }

    /**
     * 回写错误信息
     * 
     * @param message
     * @param session
     * @param e
     * @param msg
     */
    private void replyFailureMsg(final TextMessage message, Session session, String orignMsg, String errorMsg) {
        try {
            if (null != message.getJMSReplyTo()) {

                final String content = MessageUtil.getErrorResponseMessage(orignMsg, errorMsg);
                MessageCreator messageCreator = new MessageCreator() {
                    public Message createMessage(Session session) throws JMSException {
                        TextMessage replyMessage = session.createTextMessage(content);
                        replyMessage.setJMSCorrelationID(message.getJMSCorrelationID());
                        replyMessage.setStringProperty(MessageConstant.MESSAGE_ACTION, message.getJMSCorrelationID()
                                + "." + message.getStringProperty(MessageConstant.MESSAGE_ACTION));

                        return replyMessage;
                    }
                };
                logger.info("sending error message to {}", message.getJMSReplyTo().toString());
                jmsTemplate.send(message.getJMSReplyTo(), messageCreator);
            }
        } catch (Exception e1) {
            logger.error("failed to send error message to client", e1);
        }
    }
}
